#pragma once

#include<iostream>
#include<cstring>
#include<unistd.h>
#include<functional>

#include<sys/types.h>
#include<sys/socket.h>
#include <sys/wait.h>


#include"Lock.hpp"
#include"InetAddr.hpp"
#include"Log.hpp"
#include"ThreadPool.hpp"
#include"CommandExecc.hpp"


using namespace LockModule;
using namespace LogMoudle;
using namespace InetAddrMoudle;
using namespace ThreadPoolMoudle;

using handler_task=std::function<std::string(std::string)>;

#define BACKLOG 8

#define default_port 8888

class Tcpserver{

    using task_t =std::function<void()>;

    private:
    int listen_sockfd;
    uint16_t _port;
    bool _isruning;

    handler_task _handler;

    public:
    Tcpserver(handler_task handler,uint16_t port=default_port):_port(port),_isruning(false),_handler(handler)
    {

    }

    //初始化服务器的网络接口
    void Initserver()
    {
        //创建网络套接字，绑定相应的端口号
        listen_sockfd=socket(AF_INET,SOCK_STREAM,0);
        if(listen_sockfd<=0)
        {
            LOG(Logevel::INFO)<<"套接字创建失败.......";
            exit(1);
        }
        LOG(Logevel::INFO)<<"套接字创建成功,套接字是: "<<listen_sockfd;

        sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_addr.s_addr=INADDR_ANY;
        local.sin_family=AF_INET;
        local.sin_port=::htons(_port);

        //绑定套接字端口
        int n=bind(listen_sockfd,CONV(&local),sizeof(local));
        if(n<0)
        {
            LOG(Logevel::INFO)<<"套接字绑定失败.......";
            exit(1);
        }
        LOG(Logevel::INFO)<<"套接字绑定成功.......";

        //将socket设置为监听状态
        n=listen(listen_sockfd,BACKLOG);
        if(n==-1)
        {
            LOG(Logevel::INFO)<<"套接字监听失败......";
            exit(1);
        }
        LOG(Logevel::INFO)<<"套接字监听成功........";
    }

    //对接受的请求进行处理，最开始是将消息回显到客户端
    void HanderRequest(int sockfd)
    {
        LOG(Logevel::INFO)<<"HanderRequest sock is: "<<sockfd;
        char inbuffer[4096];

        while(true)
        {
            ssize_t n=::recv(sockfd,inbuffer,sizeof(inbuffer)-1,0);
            
            if(n>0)
            {
                std::cout<<"接收成功"<<std::endl;
                inbuffer[n]=0;
                LOG(Logevel::INFO)<<inbuffer;

                // std::string echo_str="server echo# ";
                // echo_str+=inbuffer;

                std::string cmd_result=_handler(inbuffer);
                send(sockfd,cmd_result.c_str(),cmd_result.size(),0);

            }
            else{
                LOG(Logevel::INFO)<<"sock close :"<<sockfd<<".....";
                break;
            }
        }
        close(sockfd);
    }

    //启动服务器,获取相应的客户端网络信息
    void Startserver()
    {
        _isruning=true;
        while(_isruning)
        {
            //读取客户端发送的消息
            sockaddr_in peer;
            socklen_t peerlen=sizeof(peer);
            LOG(Logevel::INFO)<<"accept ing.....";

            int sockfd=accept(listen_sockfd,CONV(&peer),&peerlen);
            //这里的sockfd表示相应的网络文件描述符
            if(sockfd<0)
            {
                LOG(Logevel::INFO)<<"accept is error";
                continue;
                //失败从新获取连接
            }

            LOG(Logevel::INFO)<<"accept success, sock is: "<<sockfd;

            InetAddr addr(peer);
            LOG(Logevel::INFO)<<"client info: "<<addr.PrintDebug();

            // //version-0 单向通信,这里需要进行相应的处理操作
            // HanderRequest(sockfd);

            //version-2 多进程通信,创建子进程，子进程和父进程公用一张文件描述符表
            // pid_t id=fork();
            // if(id==0)
            // {
            //     //关闭不需要的文件描述符
            //     ::close(listen_sockfd);
            //     if(fork()>0)exit(0);//子进程退出，孙子进程成为孤儿进程，会被系统自动回收
            //     HanderRequest(sockfd);
            //     exit(0);
            // }
            // ::close(sockfd);
            
            // int rid=::waitpid(id,nullptr,0);
            // if(rid<0)
            // {
            //     LOG(Logevel::INFO)<<"waitpid error";
            // }

            //version-3 线程池版本 
            task_t f=std::bind(&Tcpserver::HanderRequest,this,sockfd);//构建任务
            ThreadPool<task_t>::GetInstance()->Enqueue([this,sockfd](){this->HanderRequest(sockfd);});//将任务加入线程池
            
            
        }
        close(listen_sockfd);
    }

};